﻿using System;
using System.Collections.Generic;
using System.Linq;
using DNT.RavenQA.Core.Extensions;

namespace DNT.RavenQA.Core.Models
{
    public class ContributeVotes : Entity<Int32>
    {
        public class Vote
        {
            public String AuthorId { get; private set; }

            public Boolean Up { get; private set; }

            protected Vote() { }

            private static Vote New(User user, Boolean up)
            {
                user.EnsureIsNotNull("user");
                return new Vote { AuthorId = user.Id, Up = up };
            }

            internal static Vote NewUp(User user)
            {
                return New(user, true);
            }

            internal static Vote NewDown(User user)
            {
                return New(user, false);
            }
        }

        public String ContributeId { get; private set; }

        private IList<Vote> _votes = new List<Vote>();

        protected IList<Vote> Votes
        {
            get { return _votes; }
            private set { _votes = value; }
        }

        public Int32 TotalAmount
        {
            get { return Votes.Count(v => v.Up) - Votes.Count(v => !v.Up); }
        }

        protected ContributeVotes() { }

        public static ContributeVotes New(Contribute contribute)
        {
            contribute.EnsureIsNotNull("contribute");
            return new ContributeVotes { ContributeId = contribute.Id };
        }

        internal void New(User user, Func<User, Vote> func)
        {
            user.EnsureIsNotNull("user");
            func.EnsureIsNotNull("func");

            if (HasAlreadyVoted(user))
                throw new AlreadyVotedQuestionException();

            _votes.Add(func(user));
        }

        private Boolean HasAlreadyVoted(User user)
        {
            user.EnsureIsNotNull("user");
            return Votes.SingleOrDefault(x => x.AuthorId == user.Id).IsNotNull();
        }
    }
}